namespace Microsoft.Dynamics.AX.Framework.TeamFoundationServerFacade
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Text;

    using Microsoft.TeamFoundation.VersionControl.Client;

    /// <summary>
    /// A wrapper of Failure class
    /// </summary>
    [Serializable]
    public class FailureOrWarning
    {
        [NonSerialized]
        private Failure failure;

        /// <summary>
        /// Severity: Error or Warning
        /// </summary>
        public string Severity
        {
            get { return this.failure.Severity.ToString(); }
        }

        /// <summary>
        /// Message text
        /// </summary>
        public string Message
        {
            get { return this.failure.GetFormattedMessage(); }
        }

        /// <summary>
        /// ToString()
        /// </summary>
        /// <returns>String representation</returns>
        public override string ToString()
        {
            return this.failure.GetFormattedMessage();
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="fail">Failure</param>
        internal FailureOrWarning(Failure fail)
        {
            this.failure = fail;
        }

    }
 
    /// <summary>
    /// CheckIn() will either succeed or throw.  The Pend calls (e.g., PendEdit), Get(), etc. will use the NonFatalErrorEvent.  
    /// </summary>
    [Serializable]
    public class NonFatalErrorOutput : IEquatable<NonFatalErrorOutput>
    {
        [NonSerialized]
        private ExceptionEventArgs nonFatalError;

        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="nonFatalErrorEvent"></param>
        internal NonFatalErrorOutput(ExceptionEventArgs nonFatalErrorEvent)
        {
            this.nonFatalError = nonFatalErrorEvent;
        }

        /// <summary>
        /// Failure
        /// </summary>
        public FailureOrWarning Failure
        {
            get 
            {
                if (this.nonFatalError.Failure != null)
                    return new FailureOrWarning(this.nonFatalError.Failure);
                
                return null;
            }
        }

        /// <summary>
        /// IsException
        /// </summary>
        public bool IsException
        {
            get { return (this.nonFatalError.Exception != null); }
        }

        /// <summary>
        /// ToString
        /// </summary>
        /// <returns>String representation</returns>
        public override string ToString()
        {
            if (this.Failure != null)
            {
                return this.Failure.ToString();
            }
            else if (this.IsException)
            {
                return this.nonFatalError.Exception.Message;
            }
            else
            {
                return String.Empty;
            }

        }

        /// <summary>
        /// Equals
        /// </summary>
        /// <param name="other">Other part to compare</param>
        /// <returns>True if equal, otherwise false</returns>
        public bool Equals(NonFatalErrorOutput other)
        {
            if (other != null)
            {
                return String.Compare(other.ToString(), this.ToString(), StringComparison.OrdinalIgnoreCase) == 0;
            }
            return false;
        }
    }


    /// <summary>
    /// NonFatalErrorOutputList
    /// </summary>
    [Serializable]
    public class NonFatalErrorOutputList : List<NonFatalErrorOutput>
    { }

    /// <summary>
    /// CommandResult
    /// </summary>
    [Serializable]
    public class CommandResult
    {
        private NonFatalErrorOutputList nonFatalErrorOutputList = new NonFatalErrorOutputList();

        /// <summary>
        /// Add
        /// </summary>
        /// <param name="nonFatalErrorOutput"></param>
        internal protected void Add(NonFatalErrorOutput nonFatalErrorOutput)
        {
            if (!this.nonFatalErrorOutputList.Contains(nonFatalErrorOutput))
            {
                this.nonFatalErrorOutputList.Add(nonFatalErrorOutput);
            }
        }
        
        /// <summary>
        /// NonFatalErrorOutputList
        /// </summary>
        public NonFatalErrorOutputList NonFatalErrorOutputList
        {
            get { return this.nonFatalErrorOutputList; }
        }
    }
    
    #region PendOperation
    /// <summary>
    /// PendingChangeOutput
    /// </summary>
    [Serializable]
    public class PendingChangeOutput : IEquatable<PendingChangeOutput>
    {
        [NonSerialized]
        private PendingChangeEventArgs pendingChangeEvent;

        /// <summary>
        /// ToString()
        /// </summary>
        /// <returns>String representation</returns>
        public override string ToString()
        {
            return String.Format(CultureInfo.CurrentCulture,
                "Pending {0} on {1} with status {2}",
                PendingChange.GetLocalizedStringForChangeType(this.pendingChangeEvent.PendingChange.ChangeType),
                this.pendingChangeEvent.PendingChange.LocalItem,
                this.pendingChangeEvent.Status                
                );
        }

        /// <summary>
        /// LocalItem
        /// </summary>
        public string LocalItem
        {
            get { return this.pendingChangeEvent.PendingChange.LocalItem; }
        }

        /// <summary>
        /// Equals
        /// </summary>
        /// <param name="other">Other part to compare</param>
        /// <returns>True if equal, otherwise false</returns>
        public bool Equals(PendingChangeOutput other)
        {
            if (other != null)
            {
                return String.Compare(other.ToString(), this.ToString(), StringComparison.OrdinalIgnoreCase) == 0;
            }
            return false;
        }

        internal PendingChangeOutput(PendingChangeEventArgs ev)
        {
            this.pendingChangeEvent = ev;
        }
    }
    /// <summary>
    /// PendingChangeOutputList
    /// </summary>
    [Serializable]
    public class PendingChangeOutputList : List<PendingChangeOutput>
    { }

    /// <summary>
    /// PendOperationCommandResult
    /// </summary>
    [Serializable]
    public class PendOperationCommandResult : CommandResult
    {
        private int numberOfOperations;
        private PendingChangeOutputList pendingChangeList = new PendingChangeOutputList();

        internal PendOperationCommandResult() : base()
        {}

        /// <summary>
        /// NumberOfOperations
        /// </summary>
        public int NumberOfOperations
        {
            get { return this.numberOfOperations; }
            internal set { this.numberOfOperations = value; }
        }

        /// <summary>
        /// PendingChangeList
        /// </summary>
        public PendingChangeOutputList PendingChangeList
        {
            get
            {
                return this.pendingChangeList;
            }
        }

        internal void Add(PendingChangeOutput pendingChange)
        {
            if (!this.pendingChangeList.Contains(pendingChange))
            {
                this.pendingChangeList.Add(pendingChange);
            }
        }
    }

    #endregion

    #region Get
    /// <summary>
    /// ItemType
    /// </summary>
    [Serializable]
    public enum ItemType
    {
        /// <summary>
        /// Any
        /// </summary>
        Any = 0,
        /// <summary>
        /// Folder
        /// </summary>
        Folder = 1,
        /// <summary>
        /// File
        /// </summary>
        File = 2,
    }
    /// <summary>
    /// GetCommandOutput
    /// </summary>
    [Serializable]
    public class GetCommandOutput : IEquatable<GetCommandOutput>
    {
        [NonSerialized]
        private GettingEventArgs getEvent;
        
        /// <summary>
        /// Status
        /// </summary>
        public string Status
        {
            get { return this.getEvent.Status.ToString(); }
        }

        /// <summary>
        /// TargetLocalItem
        /// </summary>
        public string TargetLocalItem
        {
            get { return this.getEvent.TargetLocalItem; }
        }

        /// <summary>
        /// ServerItem
        /// </summary>
        public string ServerItem
        {
            get { return this.getEvent.ServerItem; }
        }

        /// <summary>
        /// ChangeType
        /// </summary>
        public string ChangeType
        {
            get { return this.getEvent.ChangeType.ToString(); }
        }

        /// <summary>
        /// IsDeleting
        /// </summary>
        public bool IsDelete
        {
            get { return this.getEvent.IsDelete; }
        }

        /// <summary>
        /// IsLatest
        /// </summary>
        public bool IsLatest
        {
            get { return this.getEvent.IsLatest; }
        }

        /// <summary>
        /// ItemType
        /// </summary>
        public ItemType ItemType
        {
            get
            {
                ItemType itemType = ItemType.Any;
                switch (this.getEvent.ItemType)
                { 
                    case Microsoft.TeamFoundation.VersionControl.Client.ItemType.Folder :
                        itemType = ItemType.Folder;
                        break;
                    case Microsoft.TeamFoundation.VersionControl.Client.ItemType.File :
                        itemType = ItemType.File;
                        break;
                    case Microsoft.TeamFoundation.VersionControl.Client.ItemType.Any:
                    default:
                        itemType = ItemType.Any;
                        break;
                }

                return itemType;
            }
        }

        /// <summary>
        /// SourceLocalItem
        /// </summary>
        public string SourceLocalItem
        {
            get { return this.getEvent.SourceLocalItem; }
        }

        /// <summary>
        /// IsRename
        /// </summary>
        public bool IsRename
        { 
            get
            {
                return String.Compare(this.SourceLocalItem, this.TargetLocalItem, StringComparison.OrdinalIgnoreCase) != 0 && 
                       this.getEvent.Status == OperationStatus.Replacing;
            }
        }

        /// <summary>
        /// ToString()
        /// </summary>
        /// <returns>string representation</returns>
        public override string  ToString()
        {
            if (this.IsDelete)
            {
                return String.Format(CultureInfo.CurrentCulture,
                    "Delete from {0} with ChangeType: {1} and Status: {2}.",
                    this.ServerItem, this.ChangeType, this.Status);
            }
            else if (this.IsRename)
            {
                return String.Format(CultureInfo.CurrentCulture,
                    "Rename from {0} to {1} with ChangeType: {2} and Status: {3}.",
                    this.SourceLocalItem, this.TargetLocalItem, this.ChangeType, this.Status);
            }
            else
            {
                return String.Format(CultureInfo.CurrentCulture,
                    "Get {0} from {1} with ChangeType: {2} and Status: {3}.",
                    this.TargetLocalItem, this.ServerItem, this.ChangeType, this.Status);
            }
        }

        /// <summary>
        /// Equals
        /// </summary>
        /// <param name="other">Other part to compare</param>
        /// <returns>True if equal, otherwise false</returns>
        public bool Equals(GetCommandOutput other)
        {
            if (other != null)
            {
                return String.Compare(other.ToString(), this.ToString(), StringComparison.OrdinalIgnoreCase) == 0;
            }
            return false;  
        }
        /// <summary>
        /// GetCommandOutput
        /// </summary>
        /// <param name="ev">GettingEventArgs</param>
        internal GetCommandOutput(GettingEventArgs ev)
        {
            this.getEvent = ev;
        }
    }

    /// <summary>
    /// GetCommandOutputList
    /// </summary>
    [Serializable]
    public class GetCommandOutputList : List<GetCommandOutput>
    { }

   
    /// <summary>
    /// GetCommandResult
    /// </summary>
    [Serializable]
    public class GetCommandResult : CommandResult
    {
        [NonSerialized]
        private GetStatus status;
        private GetCommandOutputList commandOutputs = new GetCommandOutputList();
        
        /// <summary>
        /// CommandOutputs
        /// </summary>
        public GetCommandOutputList CommandOutputs
        {
            get { return this.commandOutputs; }
        }

        /// <summary>
        /// NumFailures
        /// </summary>
        public int NumFailures
        {
            get { return this.status.NumFailures; }
        }

        /// <summary>
        /// Failures
        /// </summary>
        public ArrayList Failures
        {
            get 
            {
                ArrayList failures = new ArrayList();
                foreach (Failure failure in this.status.GetFailures())
                {
                    failures.Add(new FailureOrWarning(failure));
                }
                return failures; 
            }
        }
        /// <summary>
        /// NoActionNeeded
        /// </summary>
        public bool NoActionNeeded
        {
            get { return this.status.NoActionNeeded; }
        }

        /// <summary>
        /// NumWarnings
        /// </summary>
        public int NumWarnings
        {
            get { return this.status.NumWarnings; }
        }

        /// <summary>
        /// NumConflicts
        /// </summary>
        public int NumConflicts
        {
            get { return this.status.NumConflicts; }
        }

        /// <summary>
        /// NumOperations
        /// </summary>
        public int NumOperations
        {
            get { return this.status.NumOperations; }
        }

        /// <summary>
        /// HaveResolvableWarnings
        /// </summary>
        public bool HaveResolvableWarnings
        {
            get { return this.status.HaveResolvableWarnings; }
        }

        /// <summary>
        /// ToString
        /// </summary>
        /// <returns>String representation</returns>
        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.AppendLine(String.Format(CultureInfo.CurrentCulture, "Number of failures: {0}", this.NumFailures));
            builder.AppendLine(String.Format(CultureInfo.CurrentCulture, "Number of Warnings: {0}", this.NumWarnings));
            builder.AppendLine(String.Format(CultureInfo.CurrentCulture, "Have resolvable Warnings: {0}", this.HaveResolvableWarnings));
            builder.AppendLine(String.Format(CultureInfo.CurrentCulture, "Number of Operations: {0}", this.NumOperations));
            builder.AppendLine(String.Format(CultureInfo.CurrentCulture, "Number of Conflicts: {0}", this.NumConflicts));

            return builder.ToString();
        }
        /// <summary>
        /// Status
        /// </summary>
        internal GetStatus Status
        {
            set 
            {
                this.status = value;
            }
        }


        /// <summary>
        /// Add
        /// </summary>
        /// <param name="getCommandOutput"></param>
        internal void Add(GetCommandOutput getCommandOutput)
        {
            if (!this.commandOutputs.Contains(getCommandOutput))
            {
                this.commandOutputs.Add(getCommandOutput);
            }
        }
    }

    #endregion

    #region CheckIn
    /// <summary>
    /// CommitCheckInOutput
    /// </summary>
    [Serializable]
    public class CommitCheckInOutput
    {
        [NonSerialized]
        private CommitCheckinEventArgs commitCheckin;
        
        internal CommitCheckInOutput(CommitCheckinEventArgs commitCheckInEvent)
        {
            this.commitCheckin = commitCheckInEvent;
        }

        /// <summary>
        /// Changes
        /// </summary>
        public ChangeList Changes
        {
            get 
            {
                ChangeList changes = new ChangeList();
                foreach (PendingChange pc in this.commitCheckin.Changes)
                {
                    changes.Add(new Change(this.commitCheckin.Workspace, pc));
                }
                return changes;                
            }
        }

        /// <summary>
        /// UndoneChanges
        /// </summary>
        public ChangeList UndoneChanges
        {
            get
            {
                ChangeList undoneChanges = new ChangeList();
                foreach (PendingChange pc in this.commitCheckin.UndoneChanges)
                {
                    undoneChanges.Add(new Change(this.commitCheckin.Workspace, pc));
                }
                return undoneChanges;
            }
        }
    }
    
    /// <summary>
    /// ConflictOutput
    /// </summary>
    [Serializable]
    public class ConflictOutput : IEquatable<ConflictOutput>
    {
        [NonSerialized]
        private ConflictEventArgs conflict;

        internal ConflictOutput(ConflictEventArgs conflictEvent)
        {
            this.conflict = conflictEvent;
        }

        /// <summary>
        /// Message
        /// </summary>
        public string Message
        {
            get { return conflict.Message; }
        }

        /// <summary>
        /// Resolvable
        /// </summary>
        public bool Resolvable
        {
            get { return conflict.Resolvable; }
        }

        /// <summary>
        /// ServerItem
        /// </summary>
        public string ServerItem
        {
            get { return conflict.ServerItem; }
        }

        /// <summary>
        /// ToString
        /// </summary>
        /// <returns>String representation</returns>
        public override string ToString()
        {
            return String.Format(CultureInfo.CurrentCulture, "Conflict: {0}", this.Message);
        }

        /// <summary>
        /// Equals
        /// </summary>
        /// <param name="other">Other part to compare</param>
        /// <returns>True if equal, otherwise false</returns>
        public bool Equals(ConflictOutput other)
        {
            if (other != null)
            {
                return String.Compare(other.ToString(), this.ToString(), StringComparison.OrdinalIgnoreCase) == 0;
            }
            return false;  
        }
    }

    /// <summary>
    /// ConflictOutputList
    /// </summary>
    [Serializable]
    public class ConflictOutputList : List<ConflictOutput>
    {}

    /// <summary>
    /// CheckInError
    /// </summary>
    [Serializable]
    public class CheckInError
    {
        private ConflictOutputList conflictOutputList = new ConflictOutputList();

        /// <summary>
        /// ConflictOutputList
        /// </summary>
        public ConflictOutputList ConflictOutputList
        {
            get { return this.conflictOutputList; }
        }

        /// <summary>
        /// Add
        /// </summary>
        /// <param name="conflictOutput">ConflictOutput</param>
        internal void Add(ConflictOutput conflictOutput)
        {
            if (!this.conflictOutputList.Contains(conflictOutput))
            {
                this.conflictOutputList.Add(conflictOutput);
            }
        }
    }
    /// <summary>
    /// CheckInCommandResult
    /// </summary>
    [Serializable]
    public class CheckInCommandResult
    {
        private int changeset;
        private CommitCheckInOutput commitCheckInOutput;
        
        /// <summary>
        /// ChangeSet
        /// </summary>
        public int ChangeSet
        {
            get { return this.changeset; }
            internal set { this.changeset = value; }
        }

        /// <summary>
        /// CommitCheckInOutput
        /// </summary>
        public CommitCheckInOutput CommitCheckInOutput
        {
            get { return this.commitCheckInOutput; }
            internal set {this.commitCheckInOutput = value;}
        }

        internal CheckInCommandResult() : base()
        { }

    }
    /// <summary>
    /// ConflictResolution, wrapper class of Resolution
    /// </summary>
    [Serializable]
    public enum ConflictResolution
    {
        /// <summary>
        /// None
        /// </summary>
        None = 0,
        /// <summary>
        /// AcceptMerge
        /// </summary>
        AcceptMerge = 1,
        /// <summary>
        /// AcceptYours 
        /// </summary>
        AcceptYours = 2,
        /// <summary>
        /// AcceptTheirs
        /// </summary>
        AcceptTheirs = 3,
        /// <summary>
        /// DeleteConflict
        /// </summary>
        DeleteConflict = 4,
        /// <summary>
        /// AcceptYoursRenameTheirs
        /// </summary>
        AcceptYoursRenameTheirs = 5,
        /// <summary>
        /// OverwriteLocal
        /// </summary>
        OverwriteLocal = 6,
    }
    #endregion

}
